iT邦幫忙

2024 iThome 鐵人賽

DAY 5
1
DevOps

全端監控技術筆記---從Sentry到Opentelemetry系列 第 5

Day05--Sentry是如何獲取error? 直接手寫看看(上)

  • 分享至 

  • xImage
  •  

關於Sentry對前端error的定義

在Sentry JS SDK的原始碼中,可以在packages/utils/src/instrument的路徑下看到以下---

.
├── console.ts
├── fetch.ts
├── globalError.ts
├── globalUnhandledRejection.ts
├── handlers.ts
└── index.ts

是Sentry用來監控、覆蓋的模塊;同時,在handlers.ts中就有定義:

export type InstrumentHandlerType =
  | 'console'
  | 'dom'
  | 'fetch'
  | 'fetch-body-resolved'
  | 'history'
  | 'xhr'
  | 'error'
  | 'unhandledrejection';

可以從上述得大概,Sentry列舉了它要捕獲和監控的各種類型,而有關錯誤的就是:

  • 全局錯誤(error)--- 用於沒有被try-catch而冒泡到全局的錯誤
  • Promise錯誤(unhandledrejection )---未處理的Promise reject事件,監控那些沒有被.catch()處理的Promise
  • 其他類型的錯誤,像是在console.error的內文、網路請求、dom錯誤資訊等等,則會透過覆蓋相關方法來獲取

以下就來demo如何獲取全局錯誤和promise錯誤

如何捕獲全局錯誤

在前端的上下文中,在沒有使用try-catch來處理的異常錯誤,會拋到全局中、在瀏覽器console中出現紅字error。這時,我們可以利用覆蓋window.onerror的函數來獲取:

window.onerror = function (message, source, lineno, colno, error) {
    // maybe 上報 error
	console.log('message, source, lineno, colno, error', message, source, lineno, colno, error);
}

其中的參數:

  • message---錯誤資訊
  • source---發生錯誤的script
  • lineno---程式碼定位
  • conno---程式碼定位
  • error---Error物件

知道了這些,我們就在一個react 專案中嘗試看看:

  • demo.js中定義一個SDK,在init的時候把window.onerror給覆蓋掉:
class SelfSentry {
    init() {
        window.onerror = this._errorHandler;
    }

    _errorHandler(message, source, lineno, colno, error) {
        
        console.log(
            `Message:${message},\nSource:${source},\nLineon:${lineno},\nColno:${colno},\nError:${error}`,
        );
    }
}

export const selfSentry = new SelfSentry();
  • App.jsx的最上層引入sdk,並執行selfSentry.init();
  • 定義一個throw error函數,觸發後可以在browser console中看到:

image

代表我們真的攔截到拋到全局的error,並且可以進一步處理。

promise error

當Promise被reject、但並沒有被處理的時候,會出發unhandledrejection事件。這個可以利用覆蓋window. onunhandledrejection 來處理。

window.onunhandledrejection = function (event) {
    // maybe 上報promise error
    console.log(event)
};

那麼,我們就可以修改一下demo.js,讓它也能捕獲到promise error:

class SelfSentry {
    init() {
        window.onerror = this._errorHandler;
        window.onunhandledrejection = this._promiseErrorHandler;
    }

    _errorHandler(message, source, lineno, colno, error) {
        console.log(
            `Message:${message},\nSource:${source},\nLineon:${lineno},\nColno:${colno},\nError:${error}`,
        );
    }

    _promiseErrorHandler(event) {
        console.log(event);
    }
}

export const selfSentry = new SelfSentry();

然後再App.jsx中也mock一個promise error:

const throwPromiseError = async () => {
    const mockPromise = () =>
        new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('---promise error by myself');
            }, 500);
        });

    await mockPromise();
};

觸發後,也可以在browser console中看到捕獲的promise error 內容:

image

小結

今天我們大致了解Sentry捕獲前端error的類型,並且手寫了捕獲全局error捕獲promise error,本文的程式碼都可以在Github repository中查看。

同時要注意到,監控sdk的初始化為什麼都建議在根目錄、根節點的最上面來引入和初始化,這是為了能夠在最一開始就覆蓋全局的error處理api。

ref

ChangeLog

  • 20240920-修改、補上圖片
  • 20240919-初稿

上一篇
Day04--React與Sentry共舞
下一篇
Day06--Sentry是如何獲取error? 直接手寫看看(下)
系列文
全端監控技術筆記---從Sentry到Opentelemetry30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言